package vipyy

import (
	"fmt"
	"gitee.com/kaylee595/gkaylee/kerr"
	"github.com/imroc/req/v3"
)

type Client struct {
	httpClient *req.Client
}

type Option func(*Client)

func WithHTTPClient(client *req.Client) Option {
	return func(c *Client) {
		c.httpClient = client
	}
}

var _ = WithHTTPClient

func NewClient(options ...Option) *Client {
	c := &Client{httpClient: req.DefaultClient()}
	for _, option := range options {
		option(c)
	}
	return c
}

func (c *Client) GetHTTPClient() *req.Client { return c.httpClient }

type RespPreLogin struct {
	Success   int    `json:"success"`
	Ttokensec string `json:"ttokensec"`
	Url       string `json:"url"`
}

func (r *RespPreLogin) Error() string {
	return fmt.Sprintf("success: %d, ttokensec: %s, url: %s", r.Success, r.Ttokensec, r.Url)
}

func (c *Client) PreLogin() (*RespPreLogin, error) {
	url := "https://vip.yy.com/service/web/auth/prelogin"
	payload := map[string]string{
		"callbackURL":     "https://vip.yy.com/service/web/auth/udblogin",
		"denyCallbackURL": "https://vip.yy.com/service/web/auth/fail",
	}
	resp := c.httpClient.Post(url).
		SetHeader("Referer", "https://vip.yy.com/").
		SetFormData(payload).Do()
	if resp.Err != nil {
		return nil, resp.Err
	}
	ret := &RespPreLogin{}
	if err := resp.UnmarshalJson(ret); err != nil {
		return nil, kerr.WrapTraceStack(err)
	}
	if ret.Success != 1 {
		return nil, kerr.WrapTraceStack(ret)
	}
	return ret, nil
}

type ReqLoginAsyn struct {
	Username   string
	PwdEncrypt string
	OAuthToken string
	VK         string // 首次请求可为空, 后续请求时, 携带上一次返回的VK
	VV         string // 验证结果
}

type RespLoginAsyn struct {
	Code string `json:"code"`
	Msg  string `json:"msg"`
	Obj  struct {
		CallbackURL string      `json:"callbackURL"`
		RedirectURL string      `json:"redirectURL"`
		Vk          string      `json:"vk"`
		Vt          interface{} `json:"vt"`
		Pos         string      `json:"pos"`
		Verifyid    string      `json:"verifyid"`
		Qin         string      `json:"qin"`
		Yyuid       int         `json:"yyuid"`
		Passport    string      `json:"passport"`
		Svpic       interface{} `json:"svpic"`
		Itvjs       string      `json:"itvjs"`
		Strategy    interface{} `json:"strategy"`
	} `json:"obj"`
	Hdcode string `json:"hdcode"`
}

func (r *RespLoginAsyn) Error() string {
	return fmt.Sprintf("code: %s, msg: %s", r.Code, r.Msg)
}

func (c *Client) LoginAsyn(i ReqLoginAsyn) (*RespLoginAsyn, error) {
	url := "https://lgn.yy.com/lgn/oauth/x2/s/login_asyn.do"
	payload := map[string]string{
		"username":        i.Username,
		"pwdencrypt":      i.PwdEncrypt,
		"oauth_token":     i.OAuthToken,
		"denyCallbackURL": "https://vip.yy.com/service/web/auth/fail",
		"UIStyle":         "xelogin",
		"appid":           "5034",
		"cssid":           "5034",
		"vk":              i.VK,
		"vv":              i.VV,
		"isRemMe":         "0",
		"mxc":             "",
		"mmc":             "",
		"hiido":           "1",
	}
	resp := c.httpClient.Post(url).
		SetHeader("Referer", "https://vip.yy.com/").
		SetFormData(payload).Do()
	if resp.Err != nil {
		return nil, resp.Err
	}
	ret := &RespLoginAsyn{}
	if err := resp.UnmarshalJson(ret); err != nil {
		return nil, kerr.WrapTraceStack(err)
	}
	if ret.Code != "0" {
		return nil, kerr.WrapTraceStack(ret)
	}
	return ret, nil
}

type RespBaiduV2Submit struct {
	Code string `json:"code"`
	Msg  string `json:"msg"`
	Obj  string `json:"obj"`
}

func (r *RespBaiduV2Submit) Error() string {
	return fmt.Sprintf("code: %s, msg: %s", r.Code, r.Msg)
}

func (c *Client) BaiduV2Submit(captchaId, ds, tk, type_ string) (*RespBaiduV2Submit, error) {
	url := "https://captcha.yy.com/baiduV2/submit.do"
	payload := map[string]string{
		"appid":     "5034",
		"busiId":    "busiid",
		"captchaId": captchaId,
		"ds":        ds,
		"tk":        tk,
		"type":      type_,
	}
	resp := c.httpClient.Post(url).
		SetHeader("Referer", "https://lgn.yy.com/").
		SetFormData(payload).Do()
	if resp.Err != nil {
		return nil, resp.Err
	}
	ret := &RespBaiduV2Submit{}
	if err := resp.UnmarshalJson(&ret); err != nil {
		return nil, kerr.WrapTraceStack(err)
	}
	if ret.Code != "0" {
		return nil, kerr.WrapTraceStack(ret)
	}
	return ret, nil
}
